feat: add SQLite database persistence for game recording#8
Merged
mdgoldberg merged 22 commits intomainfrom Feb 2, 2026
Merged
Conversation
added 9 commits
January 19, 2026 03:13
- Add trailing slash to target/ for consistency - Add config.yaml to ignore user configs - Add sqlite* to ignore SQLite database files - Add .sqlx/ to ignore sqlx macro cache directory
- Add full project overview explaining Roosevelt card game simulation - Document quick start with prerequisites and installation steps - Add YAML configuration examples for various player setups - Document database persistence features and configuration priority - Explain game rules, roles, and card passing mechanics - List available AI strategies (default, random, input) - Document command-line options and database schema - Update AGENTS.md to reflect project structure changes
- Add database crate as new workspace member - Define shared workspace dependencies for all crates - Include sqlx, r2d2, tokio, async-trait, and other DB-related deps - Update Cargo.lock with all transitive dependencies
Add new database crate using sqlx with SQLite support for persisting: - Players: unique IDs, names, and creation timestamps - Games: start/end times, deck seeds, player order, config snapshots - Game results: finishing places and role assignments - Actions: all game actions with turn order and phase tracking - Failed writes: error tracking for debugging Features: - Connection pooling with r2d2 (max 20 connections) - Retry logic with exponential backoff for writes - Async trait for game recording operations - Migration-based schema management
Add config.sample.yaml with 5-player example configuration showing: - Player names and strategy selections - Delay configuration for visualization - Database URL configuration
Update simulation crate to use database persistence: - Add database dependency to Cargo.toml - Modify run_game to accept GameRecorder trait for recording games - Record all game actions (plays, sends, passes) with turn order and phase - Record game results with finishing places and roles - Add player registration flow with database lookup - Support configurable database URL via CLI, env, or YAML config
Changes to support UUID-based player identification: - CardPlay::Ord now compares by size first (Single < Pair < Triple < Quad) - GameState::new accepts (Uuid, name, strategy) tuples for player inputs - Fix inverted is_first_cardplay logic (was checking all instead of any) - Add PlayerState::new_with_id constructor with explicit UUID - Export Hand trait from lib.rs for hand detection utilities
Add integration tests for simulation crate: - test_run_game_with_default_strategies: 3-player game with default AI - test_run_game_with_mixed_strategies: mix of default and random AI - test_run_game_with_delay: verify delay functionality works - test_multiple_games: consecutive games with new player inputs Add database unit tests: - test_record_and_retrieve_player - test_record_game, test_record_action, test_record_game_result - test_finish_game, test_noop_recorder Update project documentation: - simulation/AGENTS.md: Simulation crate overview - types/AGENTS.md: Types crate documentation Fix clippy warnings: - Remove redundant tokio imports - Rename tests module to database_tests to fix module-inception
The #[tokio::main] attribute already handles tokio imports, so the explicit statement is unnecessary.
6054ae1 to
6d17b3b
Compare
6d17b3b to
4b0fd9c
Compare
Add WAL journal mode and normal synchronous mode to SQLite connection options for improved concurrency and balanced performance. Increase cache size to -64000 pages (approximately 64MB) to enhance performance during bulk write operations, preventing excessive disk I/O and improving overall database throughput. This change addresses performance bottlenecks identified in bulk data operations by leveraging SQLite's WAL mode for concurrent readers/writers and optimizing memory usage for write-heavy workloads.
4b0fd9c to
b7c2d28
Compare
added 11 commits
January 28, 2026 00:11
- Add UuidParsing variant to DatabaseError enum with From<uuid::Error> trait - Replace unwrap() call in get_player_by_name with proper error propagation - Fix closure return type to handle Result correctly Prevents application crashes when database contains malformed UUID strings.
- Replace ROOSEVELT_DATABASE with DATABASE_URL in README documentation - Aligns with Rust/SQLx ecosystem conventions - Improves tooling compatibility and developer experience Follows established patterns used by SQLx, Diesel, and major Rust applications.
Replace the old GameRecorder interface with a new DatabaseWriter trait that supports bulk and streaming implementations for flexible game recording. Core Changes: - Add DatabaseWriter trait with GameHandle-based game tracking - Implement BulkGameWriter for atomic single-transaction game recording - Implement StreamingGameWriter for real-time persistence - Add GameEventCollector for in-memory event collection - Add GameMetadata for game configuration Infrastructure: - Create database/collectors/ module for data collection types - Create database/writers/ module for writer implementations - Add GameHandle type (wrapper around i64) for game identification - Add DatabaseWriterType config enum for writer selection - Implement FromStr trait for DatabaseWriterType parsing Integration: - Update simulation/src/lib.rs to use new DatabaseWriter API - Update run_simulation.rs to use BulkGameWriter - Update integration tests for new mutable writer interface - Keep NoopRecorder for no-persistence scenarios Cleanup: - Remove old repository.rs and DatabaseRecorder - Remove legacy GameRecorder trait - Clean up lib.rs exports Bug Fixes: - Fix migrations path from ./migrations to database/migrations - Fix BulkGameWriter::record_player to actually insert players - Resolve foreign key constraint issues Documentation: - Create comprehensive database/README.md - Update AGENTS.md with new database structure - Update workspace crate count from 3 to 4 - Document writer selection configuration Testing: - Add 7 integration tests for DatabaseWriter implementations - Add unit tests for GameMetadata, GameEventCollector - Total: 15 tests passing (4 unit + 7 integration + 4 simulation) Verification: cargo test -p database -p simulation All 15 tests passing, code compiles cleanly
- Update README.md to reference DatabaseWriter instead of GameRecorder - Add reference to database/README.md for detailed DatabaseWriter docs - Update AGENTS.md to reflect test infrastructure now exists - Remove outdated 'No tests' note from AGENTS.md Verification: - grep 'GameRecorder' README.md returns no results - grep 'DatabaseWriter' README.md returns 2 matches (both updated)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new
databasecrate that enables SQLite persistence for recording games, players, and actions. Integrates with the simulation crate to automatically track all game activity.Changes
New Crate:
databaseIntegration
Documentation
Tests
Breaking Changes
GameState::newnow accepts(Uuid, name, strategy)tuples instead of(name, strategy)Usage